StoryCam 从“能生成”走向“稳定、可恢复、可并发”
本 session 围绕 StoryCam 的核心生成链路展开:先修复故事世界结构化输出不稳定的问题,再调整角色与场景资产的产品形态,随后把图片生成从同步等待升级为 Inference.sh 异步任务和前端轮询。
本 Session 摘要
visualStyle;场景资产必须无人,避免后续视频混合时出现人物一致性问题。
时间线
“这个板块期望生产的角色资产如图 2,你需要调整下生图的提示词。”
“请先把 STORYCAM_IMAGE_PROVIDER 设为 openrouter,并配置 OPENROUTER_IMAGE_MODEL。模型是:openai/gpt-5.4-image-2。”
先按用户给出的角色资产参考图调整提示词,把角色图从普通剧照改成“角色设计参考板”。随后配置图像 provider,但上游 OpenRouter 图像模型出现不稳定、拒绝、格式不可靠等问题。
结果:图像能力进入真实 provider 调试阶段,也暴露出“只靠同步请求等待模型返回”不适合多图生成。
“模型返回的故事格式不稳定,请再试一次。这个问题依然存在,需要从根上彻底解决这个问题,比如选择哪种输出格式来限制,或者需要换哪种模型来解决,同时你要给出输入和输出的 json 示例。”
“PLEASE IMPLEMENT THIS PLAN: Story World 稳定结构化输出改造计划。”
判断问题不应继续靠“再试一次”解决,而要改变输出契约:Story World 文本生成切到 DeepSeek 官方 API,使用 deepseek-v4-pro + Strict Function Calling Beta,强制调用 submit_story_world,模型只产内容,服务端补齐 id、session、版本和状态。
结果:错误从“故事格式不稳定”变成可诊断的工具调用缺失、JSON 解析失败、schema 校验失败、provider 超时等状态。
“当用户从 /storycam/story-world 生产了剧本、角色资产、场景资产,然后选择 8-9 秒、十几秒或 15-20 秒,这三种选择分别对应一组、两组、三组分镜。”
“点击一个分镜图,会以浮窗的形式打开分镜扩展画布页面,而不需要跳到一个新的页面。”
将 Core Storyboard 改成真实生成阶段:Story World 确认后,根据用户选择生成 1/2/3 个核心分镜组。每组约 15 秒,包含分镜脚本、主分镜图和最多 8 张扩展图。扩展画布作为 modal overlay 打开,不改变主流程 URL。
结果:核心分镜组成为后续视频片段生成单位,而扩展图是辅助画布,不默认触发视频生成。
“现在还有个问题,就是没有保存用户已经生成的剧本、角色资产、场景资产等,致使重启服务后,所有都需要重新再试试来一遍。”
“应该在首页……加一个‘最近项目’入口,便于用户从首页能恢复到之前做过的具体项目。”
恢复策略确定为“Supabase 数据库和私有 Storage 是唯一真实来源”。新增当前 session 恢复 API、指定 session 恢复 API、最近项目摘要 API;首页不自动跳转,只提供最近项目入口,后续流程页刷新或重启后仍自动恢复。
结果:StoryCam 从一次性生成 demo 变成可继续创作的账号项目流。
“人物资产可以根据剧本里的人物数量来定,但场景资产固定一个。”
“生成的唯一一个场景资产要像图里所示的,在一张图里足够的小切图来满足根据剧本所需的场景资产。”
角色资产改为只生成主角级或关键对手戏人物,最多 3 个;场景资产固定 1 个,并新增 scenePanels,用 4-6 个 panel 描述主场景、广角、中景、细节、光线或俯视等素材需求。
结果:场景图提示词改为 16:9 多面板环境资产板,满足后续分镜需要,同时避免生成多个割裂的地点资产。
“场景资产这页有问题,没有办法下拉,也没有生图按钮。”
“左侧进度条去掉‘输入创意’步骤,改为左上角的 logo 点击返回首页。”
“图中左上角红框‘步骤 2’去掉,角色资产红框出来的布局不对,右边有很大空白。”
围绕 Story World Review 做了一组前端修正:资产 modal 可滚动、生成按钮可见;logo 返回首页;进度条移除“输入创意”;标题上方步骤 pill 去掉;角色资产卡改为自适应铺开;底部 dock 缩小为更轻的居中浮条。
结果:页面更接近“导演工作台”的确认体验,而不是堆叠表单。
“角色资产这一次生成的偏动漫的,但是场景资产偏真实场景,这两个不协调。”
“场景资产里好几处含有人物,场景资产是不应该有人物的,要不后面生成视频和角色资产混合后会有一致性的问题。”
“角色资产是要根据剧本生成风格,如果是真人风格,那场景资产也要协同,不能什么时候角色都是漫画风格。”
新增共享视觉锚点 script.visualStyle。角色图和场景图都使用同一风格描述,不再固定日系动画或写实。场景 prompt 增加强约束:无人、无剪影、无反射人物、无身体局部、无群众。
结果:视觉一致性从“提示词感觉”上升为 Story World 输出的一部分,后续视频生成也更容易保持资产一致。
“storycam/story-world 板块里生成的剧本怎么感觉像是分镜里,有点不对,这块是剧本,下个板块才会根据剧本生成分镜脚本,具体技巧参考 docs/references/shanyin-director-master。”
明确 Story World 阶段只应生成剧本级故事材料、人物和场景资产,不输出镜头编号、机位、景别、剪辑节奏等分镜脚本信息。Core Storyboard 才负责将剧本转译成可拍摄的分镜组。
结果:产品层级更清楚:普通用户先确认故事世界,再由系统进入导演式拆解。
“现在选择 2 组和 3 组生成核心分镜的时候,接口请求都是 500,只有 1 组时能正常调用。”
“点击‘对,生成核心分镜’后按钮应该变成一个动态的状态,使得感知在执行。底栏的‘重新生成’和‘删除这个故事’两个按钮交互不需要,可以去掉。”
根因判断:接口请求内同步等待多张图片生成,2/3 组时容易超时或上游失败,导致整个 storyboard 请求 500。UI 同时缺少生成中的明确反馈。
结果:底栏只保留组数选择和主 CTA;CTA 生成中禁用并显示“正在生成核心分镜”。更重要的是,为异步图片任务改造铺路。
“看看官方 skills、cli、sdk 等操作,将现在板块里生图的操作改成可并发、异步的,比如角色资产、场景资产就是可以多线程并发,比如生成多组核心分镜也是要并发生多图。”
“Inference.sh 的一些官方核心内容要沉淀 docs,便于后面开发注意。”
查阅 Inference.sh 官方 skills 仓库后,抽取 SDK 和 CLI 关键约定:client.run(..., { wait:false }) 提交任务,client.getTask(taskId) 查询状态;CLI 对应 belt app run --no-wait 和 belt task get;图片输出通常读取 output.images。
结果:实现了 Inference.sh async image provider、图片 job 服务、Story World 批量资产图接口、Storyboard/Expansion 并发提交、前端轮询替换图片,并新增官方知识文档。
关键时刻
关键时刻 1:结构化输出不能靠“再试一次”
问题:Story World 文本格式不稳定,导致前端只能提示“模型返回的故事格式不稳定”。
为什么重要:剧本、角色资产、场景资产是后续所有生成的源头,如果源头 schema 不稳定,后续恢复、分镜和视频都会被污染。
处理:切到 DeepSeek 官方 strict function calling,强制工具调用,并把错误拆成 tool call 缺失、arguments 非 JSON、schema 不匹配、provider 失败等可诊断状态。
关键时刻 2:场景资产从“多张场景”变成“一个多切图场景板”
问题:剧本可能需要多个角度和物件细节,但产品不希望生成多个割裂的场景资产。
为什么重要:StoryCam 面向普通用户,确认资产要简单;同时视频生成需要足够多的环境参考。
处理:固定只生成一个 scene_asset,内部新增 4-6 个 scenePanels,图像提示词生成一张 16:9 环境资产板。
关键时刻 3:视觉风格被提升为 Story World 的共享字段
问题:角色资产偏动漫,场景资产偏真实,后续合成会产生风格和人物一致性问题。
为什么重要:StoryCam 不是固定风格的短剧工具,用户可能要韩剧、私人回忆、漫画、绘本或胶片感。
处理:新增 script.visualStyle,角色图和场景图共用这个风格锚点;场景图明确禁止出现任何人物、剪影、反射或身体局部。
关键时刻 4:2/3 组核心分镜 500 的根因是同步多图
问题:1 组可以生成,2/3 组接口直接 500。
为什么重要:核心分镜是从故事世界进入视频生产的关键关口,如果多组不可用,产品的 30 秒和 45 秒路径就断了。
处理:把图片生成从请求内同步等待改为 Inference.sh 异步任务;API 先返回分镜文本和 generating 图片状态,前端轮询 job,完成后替换为 signed URL。
关键时刻 5:恢复机制让 StoryCam 从 demo 变成项目工作台
问题:服务重启或刷新后,已生成的剧本、资产和分镜丢失,用户必须重来。
为什么重要:AI 生成过程成本高、耗时长,不可恢复会破坏用户信任。
处理:使用 Supabase 数据和私有 Storage 作为唯一真实来源,增加“自动恢复最新”和“最近项目”入口,不把私密素材放进 localStorage。
工程证据
- PR / Commit
- 本 session 未产生可确认的 PR 或 commit 记录。
- 关键文件
-
src/server/storycam/imageGenerationJobService.ts、src/lib/providers/inferenceSh/imageProvider.ts、src/server/storycam/storyboardService.ts、src/server/storycam/expansionService.ts、src/server/storycam/storyWorldAssetImageService.ts、src/components/storycam/StoryWorldReview.tsx、src/components/storycam/StoryCamWorkspace.tsx - 新增接口
POST /api/story-world/assets/generate-images;复用并增强GET /api/generation-jobs/:id作为图片 job 状态查询入口。- 数据库变更
supabase/migrations/20260428143000_storycam_image_generation_jobs.sql扩展generation_jobs.type,新增story_world_asset_image、storyboard_image、expanded_storyboard_image。- 文档沉淀
docs/references/inference-sh.md记录 Inference.sh SDK、CLI、task status、错误映射、图片输出和 StoryCam 异步管线;docs/references/providers.md增加链接和异步说明。- 验证命令
-
pnpm typecheckpassed;pnpm lintpassed;pnpm exec vitest run src/lib/providers/inferenceSh/imageProvider.test.ts tests/api/storyboard.test.ts tests/api/expansion.test.tspassed,3 个测试文件、13 个测试通过。 - 安全处理
- 不记录 prompt、API key、provider image URI、signed URL、私密输入或原始 provider payload;图片完成后才由服务端下载并写入私有 Storage。
- 未确认
- 本 session 未记录完整 E2E 运行结果;真实 Inference.sh 线上 smoke 结果未在聊天中确认。
对外讲解用总结
这一轮开发把 StoryCam 的核心生成体验从“单次同步调用”推进成了更接近真实产品的工作流。前半段解决的是生成内容是否可信:Story World 必须稳定地产出剧本、关键人物和唯一场景资产,且剧本不能提前变成分镜。中段解决的是资产是否可用:角色数量要跟剧本一致,场景资产要用一张多切图参考板覆盖空间需求,角色和场景必须共享视觉风格,场景不能混入人物。后半段解决的是工程可承载性:多张图片不再阻塞同一个请求,而是通过 Inference.sh 异步任务并发生成,前端轮询展示进度,失败的单张图不会拖垮整个故事或分镜组。
这一步连接了前面的“故事世界生成”和后面的“视频片段生成”:只有当剧本、资产、分镜和图片状态都能被保存、恢复、并发推进,StoryCam 才能从一个 AI 生成 demo 变成用户可以反复回到其中继续创作的导演工作台。